<template>
  <div class="quill-editor" v-loading.lock="fullscreenLoading" element-loading-text="插入中,请稍候">
    <slot name="toolbar"></slot>
    <div ref="editor"></div>

    <upload-oss
      style="display: none"
      ref="upload"
      :dir="dir"
      :auto-upload="true"
      :before-upload="handleBeforeUpload"
      :on-complete="handleUploadComplete"
    >
      <el-button type="primary" ref="uploadBtn">点击上传</el-button>
    </upload-oss>
  </div>
</template>

<script>
import { loadRemote, loadCssRemote, config } from '@vimi/utils-tool'

const quillCdn = `${config.baseUrl}/libs/quill/1.3.7/quill.min.js`
const quillStyleCdn = `${config.baseUrl}/libs/quill/1.3.7/quill.snow.min.css`
const imageDropCdn = `${config.baseUrl}/libs/quill/modules/image-drop.min.js`
const imageResizeCdn = `${config.baseUrl}/libs/quill/modules/image-resize.min.js`

const defaultOptions = {
  theme: 'snow',
  bounds: document.body,
  modules: {
    toolbar: {
      container: [
        ['bold', 'italic', 'underline', 'strike'],
        ['blockquote', 'code-block'],
        [{ list: 'ordered' }, { list: 'bullet' }],
        [{ indent: '-1' }, { indent: '+1' }],
        [{ align: [] }],
        [{ size: ['small', false, 'large', 'huge'] }],
        [{ header: [1, 2, 3, 4, 5, 6, false] }],
        // [{ 'font': [] }],
        [{ color: [] }, { background: [] }],
        ['link', 'image'],
      ],
    },
    imageResize: {
      displayStyles: {
        backgroundColor: 'black',
        border: 'none',
        color: 'white',
      },
      modules: ['Resize', 'DisplaySize', 'Toolbar'],
    },
    imageDrop: true,
    // imageExtend: {
    //   loading: true
    // }
  },
  placeholder: '请填写...',
  readOnly: false,
}

export default {
  components: {},
  props: {
    options: {
      type: Object,
      default: () => ({}),
    },
    value: String,
    content: String,
    disabled: Boolean,
    dir: {
      type: String,
      default: 'quill_file',
    },
  },
  model: {
    prop: 'value',
    event: 'change',
  },
  data() {
    return {
      quill: null,
      fullscreenLoading: false,
      innerOptions: {},
      innerContent: '',
      addRange: null,
    }
  },
  computed: {},
  watch: {
    content(val) {
      this.onValueChange(val)
    },
    value(val) {
      this.onValueChange(val)
    },
    disabled(val) {
      if (this.quill) {
        this.quill.enable(val)
      }
    },
  },
  created() {
    this.loadQuill()
  },
  mounted() {},
  methods: {
    async loadQuill() {
      loadCssRemote(quillStyleCdn)
      await loadRemote(quillCdn, 'Quill')
      await Promise.all([loadRemote(imageDropCdn), loadRemote(imageResizeCdn)])
      this.initEditor()
    },

    initEditor() {
      const { $el } = this
      if (!$el) return

      const editorRef = this.$refs.editor
      this.innerOptions = Object.assign({}, defaultOptions, this.options)
      const quill = new window.Quill(editorRef, this.innerOptions)
      this.quill = quill

      // link blot
      this.registerFileBlot(window.Quill)

      if (this.content || this.value) {
        quill.clipboard.dangerouslyPasteHTML(this.content || this.value)
      }
      quill.getModule('toolbar').addHandler('image', this.imageHandler)
      quill.enable(!this.disabled)

      quill.on('selection-change', range => {
        if (!range) {
          this.$emit('blur', quill)
        } else {
          this.$emit('focus', quill)
        }
      })

      quill.on('text-change', () => {
        let html = editorRef.children[0].innerHTML
        if (html === '<p><br></p>') {
          html = ''
        }
        const text = quill.getText()
        this.innerContent = html
        this.$emit('change', html, { html, text, quill })
      })

      this.$emit('ready', quill)
    },

    registerFileBlot(Quill) {
      const Link = Quill.import('formats/link')
      class FileBlot extends Link {
        static create(value) {
          let node
          if (value && !value.href) {
            node = super.create(value)
          } else {
            node = super.create(value.href)
            node.setAttribute('download', true)
            node.innerText = value.innerText
          }
          return node
        }
      }
      FileBlot.blotName = 'link'
      FileBlot.tagName = 'A'
      Quill.register(FileBlot)
    },

    onValueChange(newVal) {
      const { quill } = this
      if (!quill) return

      if (newVal && newVal !== this.innerContent) {
        this.innerContent = newVal
        quill.clipboard.dangerouslyPasteHTML(newVal)
      } else if (!newVal) {
        quill.setText('')
      }
    },

    imageHandler(state) {
      const { quill } = this
      if (!quill) return

      this.addRange = quill.getSelection()
      if (state) {
        // eslint-disable-next-line
        const btn = this.$refs.uploadBtn
        if (btn) {
          btn.$el.click()
        }
      }
    },

    handleBeforeUpload() {
      this.fullscreenLoading = true
    },

    handleUploadComplete(images) {
      this.fullscreenLoading = false

      const { quill } = this
      if (!quill) return

      const imgRes = images?.[0]
      if (!imgRes) return

      const rangeIndex = this.addRange?.index ?? 0
      const { type = '', url, name } = imgRes
      if (/^image/.test(type)) {
        quill.insertEmbed(rangeIndex, 'image', url, 'user')
      } else {
        quill.insertEmbed(rangeIndex, 'link', { href: url, innerText: name }, 'api')
      }
    },
  },
  beforeDestroy() {
    this.quill = null
  },
}
</script>

<style lang="scss">
.quill-editor {
  line-height: normal !important;
  // height: 438px;
}
.quill-editor .ql-container {
  height: calc(100% - 38px);
}
.ql-snow .ql-tooltip::before {
  content: '链接地址:' !important;
}
.ql-snow .ql-tooltip a.ql-action::after {
  content: '编辑' !important;
}
.ql-snow .ql-tooltip a.ql-remove::before {
  content: '删除' !important;
}
.ql-snow .ql-tooltip[data-mode='link']::before {
  content: '请输入链接地址:' !important;
}
.ql-snow .ql-tooltip.ql-editing a.ql-action::after {
  border-right: 0px;
  content: '保存';
  padding-right: 0px;
}

.ql-snow .ql-tooltip[data-mode='video']::before {
  content: '请输入视频地址:' !important;
}

.ql-snow .ql-picker.ql-size .ql-picker-label::before,
.ql-snow .ql-picker.ql-size .ql-picker-item::before {
  content: '14px' !important;
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value='small']::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value='small']::before {
  content: '10px' !important;
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value='large']::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value='large']::before {
  content: '18px' !important;
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value='huge']::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value='huge']::before {
  content: '32px' !important;
}

.ql-snow .ql-picker.ql-header .ql-picker-label::before,
.ql-snow .ql-picker.ql-header .ql-picker-item::before {
  content: '文本' !important;
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value='1']::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value='1']::before {
  content: '标题1' !important;
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value='2']::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value='2']::before {
  content: '标题2' !important;
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value='3']::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value='3']::before {
  content: '标题3' !important;
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value='4']::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value='4']::before {
  content: '标题4' !important;
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value='5']::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value='5']::before {
  content: '标题5' !important;
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value='6']::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value='6']::before {
  content: '标题6' !important;
}

.ql-snow .ql-picker.ql-font .ql-picker-label::before,
.ql-snow .ql-picker.ql-font .ql-picker-item::before {
  content: '标准字体' !important;
}
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value='serif']::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value='serif']::before {
  content: '衬线字体' !important;
}
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value='monospace']::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value='monospace']::before {
  content: '等宽字体' !important;
}
</style>
